﻿using Microsoft.AspNetCore.Mvc;
using PMS.Core.Configuration.CommonEnumConfigs;
using PMS.Core.Utils;
using PMS.Data.Entities.ScheduleTasks;
using PMS.Services.Utils;
using PMS.Services.Utils.ScheduleTasks;
using PMS.Services.Utils.Security;
using PMS.Web.Factories.ScheduleTasks;
using PMS.Web.Framework.Controllers;
using PMS.Web.Framework.Mvc.Filters;
using PMS.Web.Models;
using PMS.Web.Models.ScheduleTasks;
using System;
using System.Threading.Tasks;

namespace PMS.Web.Controllers.WebApi.AdminArea.SystemScheduleTasks
{
    public class ScheduleTaskWebApi : BaseApiController
    {
        #region Fields
        private readonly IDateTimeHelper _dateTimeHelper;
        private readonly IPermissionService _permissionService;
        private readonly IScheduleTaskFactory _scheduleTaskFactory;
        #endregion

        #region Ctor
        public ScheduleTaskWebApi(IDateTimeHelper dateTimeHelper,
            IPermissionService permissionService,
            IScheduleTaskFactory scheduleTaskFactory)
        {
            _dateTimeHelper = dateTimeHelper;
            _permissionService = permissionService;
            _scheduleTaskFactory = scheduleTaskFactory;
        }
        #endregion

        #region Methods
        [HttpGet(WebApiRouteConfig.LoadScheduleTaskByPage)]
        public IActionResult LoadScheduleTaskByPage(int Page, int PageSize)
        {
            try
            {
                var taskPagedList = _scheduleTaskFactory.PrepareScheduleTaskListModel(Page, PageSize);
                return SuccessJson("", taskPagedList);
            }
            catch (PMSException pex)
            {
                return pex.LogLevel switch
                {
                    SystemLogLevel.Warning => WarnJson(pex.Message),
                    _ => ErrorJson(pex.Message)
                };
            }
            catch (Exception ex)
            {
                return ErrorJson(ex.Message);
            }
        }

        /// <summary>
        /// 任务管理功能响应任务 启动/停止/暂停/立即执行等API调用
        /// </summary>
        /// <param name="moduleid">模块按钮权限检查参数</param>
        /// <param name="buttonid">模块按钮权限检查参数</param>
        /// <param name="taskid">任务ID</param>
        /// <param name="action">执行任务动作</param>
        /// <returns></returns>
        [AuthorizeCustomer(CustomerAuthorizeType.Admin)]
        [HttpPost(WebApiRouteConfig.TriggerScheduleTask)]
        public async Task<IActionResult> TriggerScheduleTaskApi([FromBody]ScheduleTaskAuthModel request)
        {
            try
            {
                if (!_permissionService.AdminModuleButtonAuthorize(request.ModuleId, request.ButtonId))
                    throw new PMSException(ApiResponseMessages.UnAuthorizedPermission, SystemLogLevel.Error);
                var taskModel = _scheduleTaskFactory.PrepareScheduleTaskModel(request.Id);
                if (taskModel == null)
                    throw new PMSException(ApiResponseMessages.ArgumentCannotBeNull, SystemLogLevel.Error);
                if(taskModel.Status == ScheduleJobActionStatus.Error)
                    throw new PMSException(ApiResponseMessages.TaskStatusIsError, SystemLogLevel.Error);
                var taskData = taskModel.ToEntity<SystemScheduleTask>();
                if (taskModel.LastStartTime.HasValue)
                    taskData.LastStartTimeUtc = _dateTimeHelper.ConvertToUtcTime(taskModel.LastStartTime.Value, DateTimeKind.Utc);
                if(taskModel.LastStopTime.HasValue)
                    taskData.LastStopTimeUtc = _dateTimeHelper.ConvertToUtcTime(taskModel.LastStopTime.Value, DateTimeKind.Utc);
                if (taskModel.LastSuccessTime.HasValue)
                    taskData.LastSuccessTimeUtc = _dateTimeHelper.ConvertToUtcTime(taskModel.LastSuccessTime.Value, DateTimeKind.Utc);
                (bool IsValid, string ValidateMsg) validExpression = taskData.CronExpression.IsValidExpression();
                if (!validExpression.IsValid)
                    throw new TaskCanceledException(validExpression.ValidateMsg);
                TaskJobResult jobResult = null;

                switch (request.jobAction)
                {
                    case JobAction.PauseJob:
                        switch (taskData.Status)
                        {
                            case ScheduleJobActionStatus.Paused:
                                throw new PMSException(ApiResponseMessages.DuplicationAction, SystemLogLevel.Warning);
                            case ScheduleJobActionStatus.Stop:
                                throw new PMSException(ApiResponseMessages.TaskPauseFailedFromStop, SystemLogLevel.Warning);
                            default:
                                jobResult = await TaskManager.Instance.PauseJob(taskData);
                                taskModel.Status = taskData.Status = ScheduleJobActionStatus.Paused;
                                break;
                        }
                        break;
                    case JobAction.StopJob:
                        if(taskData.Status != ScheduleJobActionStatus.Stop)
                        {
                            jobResult = await TaskManager.Instance.Stop(taskData);
                            if (jobResult.Status)
                                taskModel.Status = taskData.Status = ScheduleJobActionStatus.Stop;
                        }
                        else throw new PMSException(ApiResponseMessages.DuplicationAction, SystemLogLevel.Warning);
                        break;
                    case JobAction.ResumeJob:
                        switch(taskData.Status)
                        {
                            case ScheduleJobActionStatus.Paused:
                                jobResult = await TaskManager.Instance.Start(taskData);
                                taskModel.Status = taskData.Status = ScheduleJobActionStatus.Normal;
                                break;
                            case ScheduleJobActionStatus.Stop:
                                taskData.Status = ScheduleJobActionStatus.Normal;
                                jobResult = await TaskManager.Instance.AddScheduleJob(taskData);
                                if (jobResult.Status)
                                    taskModel.Status = ScheduleJobActionStatus.Normal;
                                break;
                            default:
                                throw new PMSException(ApiResponseMessages.DuplicationAction, SystemLogLevel.Warning);
                        }
                        break;
                    case JobAction.ExecuteJob:
                        if(taskData.Status == ScheduleJobActionStatus.Stop)
                        {
                            taskData.Status = ScheduleJobActionStatus.Normal;
                            jobResult = await TaskManager.Instance.AddScheduleJob(taskData);
                            if (!jobResult.Status)
                                break;
                            //--------------------------------------------------------
                            //弃用以下方法： 任务仅立即运行一次并继续保持停止状态
                            //触发TaskManager.Instance.ExecuteJob(taskData)将启动异步线程执行计划任务
                            //但无法控制任务线程在await TaskManager.Instance.Stop(taskData)前完成
                            //这会导致数据状态最终不一定为停止状态
                            //if(jobResult.Status && executeonly) 
                            //{
                            //    jobResult = await TaskManager.Instance.Stop(taskData);
                            //    if (jobResult.Status)
                            //        taskModel.Status = taskData.Status = ScheduleJobActionStatus.Stop;
                            //}
                            //----------------------------------------------------------
                        }
                        jobResult = await TaskManager.Instance.ExecuteJob(taskData);
                        if (jobResult.Status)
                            taskModel.Status = ScheduleJobActionStatus.Normal;
                        break;
                    default:
                        throw new NotImplementedException(nameof(request.jobAction));
                }
                  
                if (!jobResult?.Status ?? true)
                    throw new PMSException(jobResult.Message, SystemLogLevel.Error);
                
                return SuccessJson(jobResult?.Message ?? "", taskModel);
            }
            catch (PMSException pex)
            {
                return pex.LogLevel switch
                {
                    SystemLogLevel.Warning => WarnJson(pex.Message),
                    _ => ErrorJson(pex.Message)
                };
            }
            catch (Exception ex)
            {
                return ErrorJson(ex.Message);
            }
        }
        #endregion
    }
}
